package com.nulldev.util.sys.proxyswitcher;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;

import com.nulldev.util.java.ProcessUtil;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.os.OSUtil;

public class SystemProxySwitcher {
	private static final Logger log = LoggerFactory.getLogger();
	
	public static enum UseMethod {
		NativeWindows, LinuxDConf, LinuxGSettings, Unsupported;
	}
	
	public static enum ProxyMode {
		DISABLED, MANUAL;
	}
	
	public static UseMethod getMethod() {
		if (OSUtil.isWindows()) {
			return UseMethod.NativeWindows;
		}
		if (OSUtil.isLinux()) {
			return UseMethod.LinuxDConf;
		}
		return UseMethod.Unsupported;
	}
	
	public static boolean applyProxy(final UseMethod method, 
										final ProxyMode mode, final Proxy proxy) throws Exception {
		if (method == UseMethod.NativeWindows || method == UseMethod.Unsupported) {
			log.info("applyProxy() -> Unsupported method!");
			return false;
		}else if (method == UseMethod.LinuxGSettings) {
			if (mode == ProxyMode.DISABLED || (proxy != null && proxy.type() == Type.DIRECT)) {
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy mode 'none'");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https host ''");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https port 0");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http host ''");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http port 0");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks host ''");
				ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks port 0");
				return true;
			}else if (mode == ProxyMode.MANUAL) {
				final InetSocketAddress inet = (InetSocketAddress) proxy.address();
				if (proxy.type() == Type.HTTP) {
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy mode 'manual'");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https port " + + inet.getPort());
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http port " + inet.getPort());
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks host ''");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks port 0");
					return true;
				}else if (proxy.type() == Type.SOCKS) {
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy mode 'manual'");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https host ''");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.https port 0");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http host ''");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.http port 0");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("gsettings set org.gnome.system.proxy.socks port " + inet.getPort());
					return true;
				}
			}
		}else if (method == UseMethod.LinuxDConf) {
			if (mode == ProxyMode.DISABLED || (proxy != null && proxy.type() == Type.DIRECT)) {
				ProcessUtil.execCmd("dconf write /system/proxy/mode 'none'");
				ProcessUtil.execCmd("dconf write /system/proxy/https/host ''");
				ProcessUtil.execCmd("dconf write /system/proxy/https/host '0'");
				ProcessUtil.execCmd("dconf write /system/proxy/http/host ''");
				ProcessUtil.execCmd("dconf write /system/proxy/http/host '0'");
				ProcessUtil.execCmd("dconf write /system/proxy/socks/host ''");
				ProcessUtil.execCmd("dconf write /system/proxy/socks/host '0'");
				return true;
			}else if (mode == ProxyMode.MANUAL) {
				final InetSocketAddress inet = (InetSocketAddress) proxy.address();
				if (proxy.type() == Type.HTTP) {
					ProcessUtil.execCmd("dconf write /system/proxy/mode 'manual'");
					ProcessUtil.execCmd("dconf write /system/proxy/https/host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("dconf write /system/proxy/https/host " + inet.getPort());
					ProcessUtil.execCmd("dconf write /system/proxy/http/host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("dconf write /system/proxy/http/host " + inet.getPort());
					ProcessUtil.execCmd("dconf write /system/proxy/socks/host ''");
					ProcessUtil.execCmd("dconf write /system/proxy/socks/host '0'");
					return true;
				}else if (proxy.type() == Type.SOCKS) {
					ProcessUtil.execCmd("dconf write /system/proxy/mode 'manual'");
					ProcessUtil.execCmd("dconf write /system/proxy/https/host ''");
					ProcessUtil.execCmd("dconf write /system/proxy/https/host 0");
					ProcessUtil.execCmd("dconf write /system/proxy/http/host ''");
					ProcessUtil.execCmd("dconf write /system/proxy/http/host 0");
					ProcessUtil.execCmd("dconf write /system/proxy/socks/host '" + inet.getHostName() + "'");
					ProcessUtil.execCmd("dconf write /system/proxy/socks/host '" + inet.getPort() + "'");
					return true;
				}
			}
		}
		return false;
	}
	
}
